package javasec.seed;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;

import java.util.Vector;
import java.net.InetAddress;
import java.net.UnknownHostException;

import java.util.Enumeration;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;


public class ManagerSeed extends Seed implements ManagerSeedInterface
{
	private static final long serialVersionUID = 3215435448128368334L;
	Vector<Object> notifiers=new Vector<Object>(); // these are the connected clients
	public static ManagerSeed instance=null;
	HashMap<String,ArrayList<SeedNotification>> notificationLists=new HashMap<String,ArrayList<SeedNotification>>();
	
	// constructor
	public ManagerSeed() throws RemoteException
	{
		if(instance==null)instance=this;
		else throw new RemoteException("this seed has already been instantiated");
	}
	
	public String getName()
	{
		try
		{
			// return the hostname of the system
			return InetAddress.getLocalHost().getHostName();
		}
		catch (UnknownHostException e)
		{
			// if the lookup fails for some reason
			return "unknown";
		}
	}

	@Exposed(description="execute a command", arguments={"command"})
	public String exec(String command)
	{
		try
		{
			Runtime.getRuntime().exec(command);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

		return null;
	}

	public void shutdown() throws RemoteException
	{
		ManagerSeed.notifyClients(new SeedNotification("shutdown","now shutting down the seed server"));
		Runtime.getRuntime().exit(0);
	}

	public String loadSeed(String seedName, byte[] data)
	{
		// if the seeds directory does not exist, we need to create it
		File seedDir=new File(SeedServer.seedHome.getAbsolutePath()+File.separator+"seeds");
		if(seedDir.exists() && seedDir.isDirectory())
		{
			System.out.println("seeds directory exists  "+seedDir.getAbsolutePath());
		}
		else
		{
			System.out.println("making seeds dir");
			seedDir.mkdir();
		}
		
		// create a placeholder for the new file on this filesystem
		File newFile=new File(seedDir.getAbsolutePath()+File.separator+seedName+".jar");

		if(!newFile.exists()) // TODO change to an actual file compare
		{
			System.out.println("attempting to write file");
			// only do this if we don't see the jar file 
			try
			{
				//FileInputStream fis=new FileInputStream(file);
				FileOutputStream fos=new FileOutputStream(newFile);
				newFile.createNewFile();

				//byte[] buff = new byte[1024];
				//int i=0;
				//while((i=fis.read(buff))!=-1)
				//
					//System.out.println("writing "+i+" bytes");
					fos.write(data,0,data.length);
				//}

				//fis.close();
				fos.close();
			}
			catch(Exception e)
			{
				e.printStackTrace();
				return "writing the file failed";
			}
		}
		else return "remote seed is already loaded";

		return SeedServer.loadSeed(newFile);
	}

	public String unloadSeed(String seedName)
	{
		File targetSeed=new File(SeedServer.seedHome.getAbsolutePath()+File.separator+"seeds"+File.separator+seedName+".jar");
		if(!targetSeed.exists())return "this file does no exist";
		else targetSeed.delete();
		
		return null;
	}

	public ArrayList<SeedNotification> getNotifications(String queue)
	{
		if(!notificationLists.containsKey(queue))
		{
			notificationLists.put(queue,new ArrayList<SeedNotification>());
			return new ArrayList<SeedNotification>();
		}
		
		// make a shallow copy of this notification list
		ArrayList<SeedNotification> n=
			(ArrayList<SeedNotification>)notificationLists.get(queue).clone();
		
		notificationLists.get(queue).clear();
		return n;
	}
	
	public static void notifyClients(SeedNotification notification)
	{
		// add this new notification to every existing notification list
		for(ArrayList<SeedNotification> notifications: instance.notificationLists.values())
		{
			notifications.add(notification);
		}
	}

	public String addUser(String username, X509Certificate key) throws RemoteException
	{
		try
		{
			KeyStore keyStore=KeyStore.getInstance(KeyStore.getDefaultType());
			keyStore.load(new FileInputStream(SeedServer.trustedFile),SeedServer.keyPassword.toCharArray());
			
			if(keyStore.containsAlias(username))
			{
				return "name already exists";
			}

			keyStore.setCertificateEntry(username,key);
			keyStore.store(new FileOutputStream(SeedServer.trustedFile),SeedServer.keyPassword.toCharArray());
		}
		catch(Exception e)
		{
			System.out.println(e);
		}
		
		return "success";
	}

	public String deleteUser(String username)
	{
		System.out.println("deleting user "+username);
		
		try
		{
			KeyStore keyStore=KeyStore.getInstance(KeyStore.getDefaultType());
			keyStore.load(new FileInputStream(SeedServer.seedHome+File.separator+"seed-trusted.key"),SeedServer.keyPassword.toCharArray());
			
			if(keyStore.containsAlias(username))
			{
				keyStore.deleteEntry(username);
				keyStore.store(new FileOutputStream(SeedServer.trustedFile),SeedServer.keyPassword.toCharArray());
				return "success";
			}
			else return "user does not exist";
			
		}
		catch(Exception e)
		{
			System.out.println(e);
		}
		
		return null;
	}

	public ArrayList<String> listUsers() throws RemoteException
	{
		ArrayList<String> result=new ArrayList<String>();
		
		try
		{
			KeyStore keyStore=KeyStore.getInstance(KeyStore.getDefaultType());
			keyStore.load(new FileInputStream(SeedServer.seedHome+File.separator+"seed-trusted.key"),SeedServer.keyPassword.toCharArray());
		
			// convert the enumeration to an arraylist
			result=new ArrayList<String>();
			Enumeration<String> aliases=keyStore.aliases();
			while(aliases.hasMoreElements())result.add(aliases.nextElement());
		}
		catch(Exception e)
		{
			System.out.println(e);
			return null;
		}
		
		return result;
	}

	public int readPipe(int pipeID, String data) throws RemoteException
	{
		// TODO Auto-generated method stub
		return 0;
	}

	public int writePipe(int pipeID, String data) throws RemoteException
	{
		// TODO Auto-generated method stub
		return 0;
	}
}
